home *** CD-ROM | disk | FTP | other *** search
/ Mac Mania 2 / MacMania 2.toast / Demo's / Tools&Utilities / Programming / MacStarter Pascal 1.0 / xWindows definition files / xInputDecoration.p < prev    next >
Encoding:
Text File  |  1993-02-16  |  15.5 KB  |  570 lines  |  [TEXT/PJMM]

  1. unit xInputDecoration;
  2.  
  3. { The "decorations" defined in this unit are boxes into which the user can type }
  4. { strings.  You can then retrieve the strings typed.  Subclasses of the basic }
  5. { xStringInput restrict the type of input allowed (for example, to integers in }
  6. { a specified range).  Procedures are provided for you to retrieve the values }
  7. { entered. }
  8. {    If you have several of these decorations in a window, then pressing the tab}
  9. { key will move from one to another (just as it would in a dialog box). }
  10. {     You should not use an xStringInput in an xTetWindow unless you have locked the }
  11. { text in that window.  (Otherwise, the system won't know what to do with key }
  12. { presses.) }
  13.  
  14. interface
  15.  
  16. uses
  17.     xWindow;
  18.  
  19. type
  20.     xStringInput = object(xWindowDecoration)
  21.             { a box in which the user can type a string, that you can later retrieve }
  22.             TE: TEHandle;  { holds the text }
  23.             maxLength: integer;  { maximum allowed length of string; set to 255 by default }
  24.             procedure SetUp (win: xWindow;
  25.                                         theLeft, theTop, theWidth, theHeight: integer);
  26.            { Installs the xStringInput in the given window at the specified location. }
  27.            { The meanings of theLeft, theTop, theWidth and theHeight are not }
  28.            { straightforward when the numbers are not positive; see the discussion in }
  29.            { the comments on procedure xWindowDecoration.Install in unit xWindow.p }
  30.            { Note: theHeight will generally be of the form 16*n+8, where n is the }
  31.            {          number of lines of text you want to allow.  (This assumes the }
  32.            {          standard application font. ) }
  33.             procedure SetContents (str: string);
  34.            { Put the specified string into the box; use this to provide a default value, }
  35.            { for example. }
  36.             procedure GetContents (var str: string);
  37.            { Get the string currently in the box. }
  38.             procedure Hilite (rangeStart, rangeEnd: integer);
  39.            { Hilite a range of characters in the string.  Use Hilite(0,255) to hilite the }
  40.            { entire string; use Hiilite(n,n) to set the insertion point to a position after }
  41.            { the n-th character }
  42.             procedure SetMaxLength (max: integer);
  43.            { Set the maximum allowed length for the string entered by the user.  If the }
  44.            { attempts to type more characters, the computer will beep. }
  45.             procedure doTab;
  46.            { move to next xStringInput in the window, hiliting its contents; called }
  47.            { automatically when user presses the tab key. }
  48.             procedure doKey (ch: char;
  49.                                         modifiers: longint);  { process a key press }
  50.             override;
  51.             procedure doClick (localPt: point;  { process a mouse click }
  52.                                         modifiers: longint);
  53.             override;
  54.             procedure doDraw;  { redraw the box when necessary }
  55.             override;
  56.             procedure kill;   { remove the box and delete its storage }
  57.             override;
  58.             procedure adjustSize;  { react to change in size of window }
  59.             override;
  60.             procedure doActivate (active: boolean);  { react to window activation/deactivation }
  61.             override;
  62.             procedure idle;   { the idle for a string box involves blinking the cursor }
  63.             override;
  64.             procedure hide;   { hide the box }
  65.             override;
  66.             procedure show;  { show the box again }
  67.             override;
  68.             procedure select;
  69.            { deselects any currently active xStringInput, and selects this one }
  70.         end;
  71.  
  72.     xIntegerInput = object(xStringInput)
  73.            { an xStringInput in which the user must type an integer. Characters that }
  74.            { cannot occur in an integer will be rejected, and the computer will beep }
  75.             maxVal, minVal: longint;  { the minimum and maximum values that will be }
  76.                 { accepted; the ERR parameter in GetNumber will be set to true }
  77.                 { if the number lies outside  this range. }
  78.             displayAlertOnError: boolean;  { if this is set to true (the default value), the }
  79.                 { user will be alerted by an alert box if the contents of the input box }
  80.                 { do not represent a legal integer in the specified range when you }
  81.                 { call get number; if it is false, the ERR parameter will be set, but the  }
  82.                 { user will not be informed of the error. }
  83.             procedure SetLegalRange (min, max: longint);
  84.                 { Change the maximum and minimum values that you will accept; by default,}
  85.                 { these are MaxLongint and -MaxLongint, giving no restriction at all. }
  86.             procedure GetNumber (var n: longint;
  87.                                         var err: boolean);
  88.                 { Retrieved the number entered by the user.  If it is not a legal number in }
  89.                 { the specified range, n will be undefined and ERR will be set to TRUE. }
  90.                 { Note that you can still call the procedure GetContents to get the STRING }
  91.                 { entered by the user. }
  92.             procedure SetContentsToNumber (n: longint);
  93.                 { Enter a number into the box. }
  94.             procedure SetUp (win: xWindow;
  95.                                         theLeft, theTop, theWidth, theHeight: integer);
  96.             override;
  97.            { same function as overridden procedure }
  98.             procedure doKey (ch: char;
  99.                                         modifiers: longint);
  100.             override;
  101.           { modifies doKey to reject illegal characters. }
  102.         end;
  103.  
  104.  
  105.     xRealInput = object(xStringInput)
  106.          { Same description as xIntegerInput, except that real numbers are used. }
  107.          { Exponential form is allowed, as long as there are three digits or fewer in }
  108.          { the exponent. }
  109.             maxVal, minVal: extended;
  110.             displayAlertOnError: boolean;
  111.             procedure SetLegalRange (min, max: extended);
  112.             procedure GetNumber (var n: extended;
  113.                                         var err: boolean);
  114.             procedure SetContentsToNumber (n: extended);
  115.             procedure SetUp (win: xWindow;
  116.                                         theLeft, theTop, theWidth, theHeight: integer);
  117.             override;
  118.             procedure doKey (ch: char;
  119.                                         modifiers: longint);
  120.             override;
  121.         end;
  122.  
  123.  
  124. implementation
  125.  
  126.  
  127. procedure xStringInput.select;
  128. { deselects any currently active xStringInput, and selects s }
  129.     var
  130.         d: xWindowDecoration;
  131.         xWin: xWindow;
  132.     begin
  133.         xWin := itsWindow;
  134.         if (xWin = nil) then
  135.             EXIT(select);
  136.         d := xWin.decorations;
  137.         while d <> nil do begin
  138.                 if member(d, xStringInput) & d.wantsKey then begin
  139.                         d.wantsKey := false;
  140.                         d.doActivate(false);
  141.                     end;
  142.                 d := d.nextDecoration;
  143.             end;
  144.         wantsKey := true;
  145.         doActivate(true);
  146.         TESetSelect(0, 32000, TE);
  147.     end;
  148.  
  149.  
  150. procedure xStringInput.SetUp (win: xWindow;
  151.                                 theLeft, theTop, theWidth, theHeight: integer);
  152.     var
  153.         savePort: GrafPtr;
  154.         R: Rect;
  155.         ch: cursHandle;
  156.     begin
  157.         if win.theWindow = nil then
  158.             EXIT(setup);
  159.         init;
  160.         GetPort(savePort);
  161.         SetPort(win.theWindow);
  162.         SetRect(R, 0, 0, 10, 10);
  163.         TE := TENew(R, R); { junk }
  164.         TEAutoView(true, TE);
  165.         SetPort(savePort);
  166.         Install(win, theLeft, theTop, theWidth, theHeight);
  167.         adjustSize;
  168.         maxLength := 255;
  169.         wantsClick := true;
  170.         ch := getCursor(iBeamCursor);
  171.         if ch <> nil then begin
  172.                 useCursor(ch^^);
  173.             end;
  174.         select
  175.     end;
  176.  
  177. procedure xStringInput.SetContents (str: string);
  178.     var
  179.         R: rect;
  180.         savePort: GrafPtr;
  181.         win: WindowPtr;
  182.     begin
  183.         if str = '' then
  184.             TESetText(@str, 0, TE)
  185.         else
  186.             TESetText(@str[1], length(str), TE);
  187.         R := TE^^.viewRect;
  188.         GetPort(savePort);
  189.         win := itsWindow.theWindow;
  190.         SetPort(win);
  191.         EraseRect(R);
  192.         TEUpdate(R, TE);
  193.         SetPort(savePort);
  194.     end;
  195.  
  196. procedure xStringInput.GetContents (var str: string);
  197.     var
  198.         s: str255;
  199.     begin
  200.         GetIText(TE^^.hText, s);
  201.         str := s
  202.     end;
  203.  
  204. procedure xStringInput.Hilite (rangeStart, rangeEnd: integer);
  205.     begin
  206.         if not wantsKey then
  207.             select;
  208.         TESetSelect(rangeStart, rangeEnd, TE);
  209.     end;
  210.  
  211. procedure xStringInput.SetMaxLength (max: integer);
  212.     begin
  213.         maxLength := max;
  214.         if max < 1 then
  215.             maxLength := 1
  216.         else if maxLength > 255 then
  217.             maxLength := 255;
  218.     end;
  219.  
  220. procedure xStringInput.doTab;
  221.     var
  222.         win: xWindow;
  223.         d: xWindowDecoration;
  224.         startOver: boolean;
  225.     begin
  226.         if (itsWindow <> nil) & (itsWindow.decorations <> nil) then begin
  227.                 win := itsWindow;
  228.                 d := self;
  229.                 startOver := false;
  230.                 repeat
  231.                     d := d.nextDecoration;
  232.                     if d = nil then begin
  233.                             if startover then
  234.                                 EXIT(doTab) { impossible error : self not found }
  235.                             else begin
  236.                                     startOver := true;
  237.                                     d := win.decorations;
  238.                                 end;
  239.                         end;
  240.                 until (d = self) | (member(d, xStringInput) & d.visible);
  241.                 if d <> nil then
  242.                     xStringInput(d).select;
  243.             end;
  244.     end;
  245.  
  246. procedure xStringInput.doKey (ch: char;
  247.                                 modifiers: longint);
  248.     begin
  249.         if not wantsKey then
  250.             EXIT(doKey);
  251.         if ch = chr(9) then
  252.             doTab
  253.         else if (ch in [chr(8), chr($1C)..chr($1F)]) | (TE^^.teLength < maxLength) | (TE^^.selEnd > TE^^.selStart) then
  254.             TEKey(ch, TE)
  255.         else
  256.             Sysbeep(5);
  257.     end;
  258.  
  259. procedure xStringInput.doClick (localPt: point;
  260.                                 modifiers: longint);
  261.     var
  262.         win: xWindow;
  263.         shifted: boolean;
  264.     begin
  265.         if not wantsKey then
  266.             select;
  267.         if wantsKey & PtInRect(localPt, TE^^.viewRect) then begin
  268.                 shifted := BitAnd(modifiers, shiftKey) <> 0;
  269.                 TEClick(localPt, shifted, TE);
  270.             end
  271.     end;
  272.  
  273. procedure xStringInput.doDraw;
  274.     var
  275.         R: Rect;
  276.     begin
  277.         R := TE^^.viewRect;
  278.         TEUpdate(R, TE);
  279.         InsetRect(R, -4, -4);
  280.         FrameRect(R);
  281.     end;
  282.  
  283. procedure xStringInput.kill;
  284.     begin
  285.         TEDispose(TE);
  286.         inherited kill
  287.     end;
  288.  
  289. procedure xStringInput.adjustSize;
  290.     var
  291.         savePort: GrafPtr;
  292.     begin
  293.         inherited adjustSize;
  294.         if drawRect.bottom - drawRect.top < TE^^.lineHeight + 8 then
  295.             drawRect.bottom := drawRect.top + TE^^.lineHeight + 8;
  296.         if drawRect.right - drawRect.left < 30 then
  297.             drawRect.right := drawRect.left + 30;
  298.         clickRect := drawRect;
  299.         InsetRect(clickRect, 4, 4);
  300.         TE^^.viewRect := clickRect;
  301.         TE^^.destRect := clickRect;
  302.         TECalText(TE);
  303.         if (itsWindow <> nil) & (itsWindow.theWindow <> nil) then begin
  304.                 GetPort(savePort);
  305.                 SetPort(itsWindow.theWindow);
  306.                 InvalRect(drawRect);
  307.                 SetPort(savePort);
  308.             end;
  309.     end;
  310.  
  311. procedure xStringInput.doActivate (active: boolean);
  312.     begin
  313.         if active and wantsKey then
  314.             TEActivate(TE)
  315.         else
  316.             TEDeactivate(TE);
  317.     end;
  318.  
  319. procedure xStringInput.idle;
  320.     begin
  321.         if wantsKey then
  322.             TEIdle(TE);
  323.     end;
  324.  
  325. procedure xStringInput.hide;
  326.     begin
  327.         if wantsKey & (itsWindow <> nil) then begin
  328.                 doTab;
  329.                 if wantsKey then begin
  330.                         wantsKey := false;
  331.                         doActivate(false);
  332.                     end;
  333.             end;
  334.         inherited hide;
  335.     end;
  336.  
  337. procedure xStringInput.show;
  338.     var
  339.         d: xWindowDecoration;
  340.         activeTE: boolean;
  341.     begin
  342.         if itsWindow <> nil then begin
  343.                 d := itsWindow.decorations;
  344.                 activeTE := false;
  345.                 while d <> nil do begin
  346.                         if member(d, xStringInput) & d.wantsKey then begin
  347.                                 activeTE := true;
  348.                                 leave
  349.                             end;
  350.                         d := d.nextDecoration;
  351.                     end
  352.             end
  353.         else
  354.             activeTE := true;
  355.         inherited show;
  356.         if not activeTE then begin
  357.                 wantsKey := true;
  358.                 if (itsWindow <> nil) & (itsWindow.theWindow <> nil) & (itsWindow.theWindow = FrontWindow) then
  359.                     doActivate(true);
  360.             end;
  361.     end;
  362.  
  363. {$PUSH}
  364. {$R-}
  365.  
  366. procedure RealToString (x: extended;
  367.                                 var s: string);
  368.     var
  369.         n, i: integer;
  370.     begin
  371.         if abs(x) < 1e-2000 then
  372.             s := '0'
  373.         else if (abs(x) >= 5e8) or (abs(x) < 5e-8) then begin  { exponential form }
  374.                 n := 15;
  375.                 repeat  { this is needed since the stupid computer allows 4 spaces for the exponent even if it is one two or three digits }
  376.                     s := StringOf(x : n);
  377.                     n := n - 1;
  378.                     i := length(s);
  379.                     while (i > 0) & (s[i] = ' ') do
  380.                         i := i - 1;
  381.                     s[0] := chr(i);
  382.                 until (length(s) <= 12) | (n = 11)
  383.             end
  384.         else begin
  385.                 s := StringOf(x : 1 : 10);
  386.                 i := length(s);
  387.                 while (i > 1) & (s[i] = '0') do   { strip off trailing zeros }
  388.                     i := i - 1;
  389.                 if (i > 0) & (s[i] = '.') then  { strip off terminating decimal point }
  390.                     i := i - 1;
  391.                 if i > 12 then  { maximum length allowed for output is 12}
  392.                     s[0] := chr(12)
  393.                 else
  394.                     s[0] := chr(i);
  395.             end
  396.     end;
  397.  
  398. {$POP}
  399.  
  400.  
  401.  
  402. procedure GetNum (var str: string;
  403.                                 var x: extended;
  404.                                 var err: boolean);
  405.     var
  406.         i, ct, len: integer;
  407.     begin
  408.         i := 1;
  409.         len := length(str);
  410.         while (i <= len) & (str[i] = ' ') do
  411.             i := i + 1;
  412.         if (i < len) & ((str[i] = '-') or (str[i] = '+')) then
  413.             i := i + 1;
  414.         while (i <= len) & (str[i] in ['0'..'9']) do
  415.             i := i + 1;
  416.         if (i <= len) & (str[i] = '.') then begin
  417.                 i := i + 1;
  418.                 while (i <= len) & (str[i] in ['0'..'9']) do
  419.                     i := i + 1;
  420.             end;
  421.         ct := 0;
  422.         if (i < len) & ((str[i] = 'e') | (str[i] = 'E')) then begin
  423.                 i := i + 1;
  424.                 if (i < len) & ((str[i] = '-') | (str[i] = '+')) then
  425.                     i := i + 1;
  426.                 while (i <= len) & (str[i] in ['0'..'9']) do begin
  427.                         i := i + 1;
  428.                         ct := ct + 1
  429.                     end;
  430.             end;
  431.         err := not ((i > len) & (ct <= 3));
  432.         if not err then begin
  433.                 IOCheck(false);
  434.                 ReadString(str, x);
  435.                 IOCheck(True);
  436.                 if IOResult <> noErr then
  437.                     err := true;
  438.             end;
  439.     end;
  440.  
  441. procedure xIntegerInput.SetLegalRange (min, max: longint);
  442.     begin
  443.         if max > min then begin
  444.                 minVal := min;
  445.                 maxVal := max;
  446.             end;
  447.     end;
  448.  
  449. procedure xIntegerInput.GetNumber (var n: longint;
  450.                                 var err: boolean);
  451.     var
  452.         str: string;
  453.         x: extended;
  454.     begin
  455.         GetContents(str);
  456.         GetNum(str, x, err);
  457.         if not err then begin
  458.                 if (x < minVal) | (x > maxVal) then
  459.                     err := true
  460.                 else
  461.                     n := round(x);
  462.             end;
  463.         if err & displayAlertOnError then begin
  464.                 str := StringOf('You must type in a legal integer in the range between ', minVal : 1, ' and ', maxVal : 1, '.');
  465.                 TellUser(str);
  466.                 select;
  467.                 TESetSelect(0, 32000, TE);
  468.             end;
  469.     end;
  470.  
  471. procedure xIntegerInput.SetContentsToNumber (n: longint);
  472.     begin
  473.         SetContents(StringOf(n : 1));
  474.     end;
  475.  
  476. procedure xIntegerInput.SetUp (win: xWindow;
  477.                                 theLeft, theTop, theWidth, theHeight: integer);
  478.     begin
  479.         inherited setUp(win, theLeft, theTop, theWidth, theHeight);
  480.         TEAutoView(false, TE);
  481.         TE^^.crOnly := -1;  { no auto word wrap }
  482.         minVal := -maxLongInt;
  483.         maxVal := maxLongint;
  484.         displayAlertOnError := true;
  485.         SetMaxLength(25);
  486.     end;
  487.  
  488. procedure xIntegerInput.doKey (ch: char;
  489.                                 modifiers: longint);
  490.     begin
  491.         if not wantsKey then
  492.             EXIT(doKey);
  493.         if ch in ['0'..'9', '+', '-', chr(8), chr(9), chr($1C)..chr($1F)] then
  494.             inherited doKey(ch, modifiers)
  495.         else
  496.             Sysbeep(5);
  497.     end;
  498.  
  499. procedure xRealInput.SetLegalRange (min, max: extended);
  500.     begin
  501.         if max > min then begin
  502.                 minVal := min;
  503.                 maxVal := max;
  504.             end;
  505.     end;
  506.  
  507. procedure xRealInput.GetNumber (var n: extended;
  508.                                 var err: boolean);
  509.     var
  510.         str: string;
  511.         x: extended;
  512.         minStr, maxStr: string;
  513.     begin
  514.         GetContents(str);
  515.         GetNum(str, x, err);
  516.         if not err then begin
  517.                 if (x < minVal) | (x > maxVal) then
  518.                     err := true
  519.                 else
  520.                     n := x;
  521.             end;
  522.         if err & displayAlertOnError then begin
  523.                 RealToString(minVal, minStr);
  524.                 RealToString(maxVal, maxStr);
  525.                 if (minVal > -1e1000) & (maxVal < 1e1000) then
  526.                     str := StringOf('You must type in a legal real number in the range between ', minStr, ' and ', maxStr, '.')
  527.                 else if (minVal > -1e1000) then
  528.                     str := Concat('You must type in a legal real number, greater than ', minStr)
  529.                 else if (maxVal < 1e1000) then
  530.                     str := Concat('You must type in a legal real number, less than ', maxStr)
  531.                 else
  532.                     str := 'You must type in a legal real number.';
  533.                 TellUser(str);
  534.                 select;
  535.                 TESetSelect(0, 32000, TE);
  536.             end;
  537.     end;
  538.  
  539. procedure xRealInput.SetContentsToNumber (n: extended);
  540.     var
  541.         str: string;
  542.     begin
  543.         RealToString(n, str);
  544.         SetContents(str);
  545.     end;
  546.  
  547. procedure xRealInput.SetUp (win: xWindow;
  548.                                 theLeft, theTop, theWidth, theHeight: integer);
  549.     begin
  550.         inherited setUp(win, theLeft, theTop, theWidth, theHeight);
  551.         TEAutoView(false, TE);
  552.         TE^^.crOnly := -1;  { no auto word wrap }
  553.         minVal := -1e1000;
  554.         maxVal := 1e1000;
  555.         displayAlertOnError := true;
  556.         SetMaxLength(50);
  557.     end;
  558.  
  559. procedure xRealInput.doKey (ch: char;
  560.                                 modifiers: longint);
  561.     begin
  562.         if not wantsKey then
  563.             EXIT(doKey);
  564.         if ch in ['0'..'9', '+', '-', 'e', 'E', '.', chr(8), chr(9), chr($1C)..chr($1F)] then
  565.             inherited doKey(ch, modifiers)
  566.         else
  567.             Sysbeep(5);
  568.     end;
  569.  
  570. end.